package com.lilingguo.easyserver.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.lilingguo.easyserver.container.Container;
import com.lilingguo.easyserver.container.DefaultContainer;
import com.lilingguo.easyserver.container.MapdbContainer;
import com.lilingguo.easyserver.dao.ServiceInfoDao;
import com.lilingguo.easyserver.container.SqlContainer;
import com.lilingguo.easyserver.pojo.Monitor;
import com.lilingguo.easyserver.pojo.Persistence;
import com.lilingguo.easyserver.pojo.ServiceInfo;
import lombok.extern.log4j.Log4j2;
import org.mapdb.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.client.RestTemplate;

import javax.sql.DataSource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 容器配置类
 *
 * @Author: 黎铃果
 * @Date: 2020/05/28 16:31
 */
@Log4j2
@Configuration
@ComponentScan("com.lilingguo.easyserver")
@AutoConfigureAfter
public class ContainerConfigure {

    @Autowired
    private ServerProperties serverProperties;
    @Autowired
    private DataSourceProperties dataSourceProperties;

    /**
     * DataSource
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "easyserver.server.storage-mode", havingValue = "sql")
    public DataSource druidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
        dataSource.setUrl(dataSourceProperties.getUrl());
        dataSource.setUsername(dataSourceProperties.getUsername());
        dataSource.setPassword(dataSourceProperties.getPassword());
        return dataSource;
    }

    /**
     * JdbcTemplate
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean({DataSource.class})
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    /**
     * 数据库容器
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean({JdbcTemplate.class, ServiceInfoDao.class})
    public Container sqlContainer(ServiceInfoDao serviceInfoDao) {
        log.info("using SqlContainer");
        return new SqlContainer(serviceInfoDao);
    }

    /**
     * MapDB容器 (memory db)
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "easyserver.server.storage-mode", havingValue = "mapdb")
    public Container mapdbContainer() {
        log.info("using MapdbContainer");
        DB db = DBMaker.memoryDB().make();
        ConcurrentMap<String, ServiceInfo> map =
                (ConcurrentMap<String, ServiceInfo>) db.hashMap("test")
                        .keySerializer(Serializer.STRING)
                        .createOrOpen();
        return new MapdbContainer(map);
    }

    /**
     * 默认内存容器
     */
    @Bean
    @ConditionalOnMissingBean
    public Container defaultContainer() {
        log.info("using DefaultContainer");
        return new DefaultContainer(new ConcurrentHashMap<String, ServiceInfo>(128));
    }

    /**
     * 监听服务状态
     */
    @Bean
    @ConditionalOnMissingBean
    public Monitor monitorInfo() {
        return new Monitor();
    }

    /**
     * 持久化对象
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean({Container.class})
    public Persistence persistence() {
        String path = serverProperties.getDataPersistencePath();
        if (path != null) {
            log.info("using file persistence at " + path);
            return new Persistence(path);
        }
        return null;
    }

    /**
     * RestTemplate
     */
    @Bean
    @ConditionalOnMissingBean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}
